package com.bestcem.xm.survey.export.type;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.survey.export.BaseTypeHandler;
import com.bestcem.xm.survey.grpc.client.dto.QstructsDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import static com.bestcem.xm.survey.enums.QuestionTypeEnum.QUESTION_TYPE_MATRIX_SINGLE;

/**
 * 矩阵单选
 */
@Slf4j
@Component
public class MatrixSingleHandler implements BaseTypeHandler {

    @Override
    public Map<String, String> getSelectColumnChangeDictV2(JSONObject data, String dtype) {
        Map<String, String> column_change_dict = new HashMap();
        //选项选项
        List<JSONObject> items = (List<JSONObject>) data.getOrDefault("rows_items", Collections.emptyList());
        items.forEach(v -> column_change_dict.put(getSelectRealcolV2(data, v), getSelectReadablecolV2(data, v)));
        return column_change_dict;
    }

    private String getSelectRealcolV2(JSONObject data, JSONObject item) {
        return String.format("%s__%s", data.getString("cid"), item.get("oid"));
    }

    private String getSelectReadablecolV2(JSONObject data, JSONObject item) {
        //cid:题目可见编号
        return String.format("%s__%s", BaseTypeHandler.clearHtml(data.getString("title")), BaseTypeHandler.clearHtml((String) item.getOrDefault("title", "")));
    }

    @Override
    public Map<String, String> getOpenColumnChangeDictV2(JSONObject data) {
        Map<String, String> res = new HashMap();
        List<JSONObject> rows_items = (List<JSONObject>) data.getOrDefault("rows_items", Collections.emptyList());
        List<JSONObject> items = (List<JSONObject>) data.getOrDefault("items", Collections.emptyList());
        rows_items.forEach(v -> {
            if (isOpenRow(v)) {
                res.put(getOpenRealcolV2(data, v, null), getOpenReadablecolV2(data, v, null));
            }
            items.forEach(s -> {
                if (isOpenOption(s)) {
                    res.put(getOpenRealcolV2(data, v, s), getOpenReadablecolV2(data, v, s));
                }
            });
        });
        return res;
    }

    private String getOpenRealcolV2(JSONObject data, JSONObject row, JSONObject item) {
        if (Objects.isNull(item)) {
            return String.format("%s__%s__row__open", data.getString("cid"), row.getString("id"));
        }
        return String.format("%s__%s__%s__open", data.getString("cid"), row.getString("id"), item.getString("id"));
    }

    private String getOpenReadablecolV2(JSONObject data, JSONObject row, JSONObject item) {
        if (Objects.isNull(item)) {
            return String.format("%s__%s__开放", BaseTypeHandler.clearHtml(data.getString("title")), BaseTypeHandler.clearHtml(row.getString("title")));
        }
        return String.format("%s__%s__%s__开放", BaseTypeHandler.clearHtml(data.getString("title")), BaseTypeHandler.clearHtml(row.getString("title")), BaseTypeHandler.clearHtml(item.getString("title")));
    }

    @Override
    public Map<String, String> getScoreColumnChangeDictV2(JSONObject data, QstructsDto qStruct) {
        Map<String, String> res = new HashMap();
        JSONObject scores = JSONObject.parseObject(qStruct.getScores());
        if (!scores.isEmpty() && scores.containsKey(data.getString("gid"))) {
            res.put(getScoreRealcolV2(data), getScoreReadablecolV2(data));
        }
        return res;
    }

    private String getScoreRealcolV2(JSONObject data) {
        return String.format("%s__score", data.getString("cid"));
    }

    private String getScoreReadablecolV2(JSONObject data) {
        return String.format("%s__评分", BaseTypeHandler.clearHtml(data.getString("title")));
    }

    @Override
    public List<String> getSelectColumnListV2(JSONObject data, String dtype) {
        List<String> column_list = new ArrayList();
        List<JSONObject> rows_items = (List<JSONObject>) data.getOrDefault("rows_items", Collections.emptyList());
        rows_items.forEach(v -> column_list.add(getSelectRealcolV2(data, v)));
        return column_list;
    }

    @Override
    public List<String> getOpenColumnListV2(JSONObject data) {
        List<String> res = new ArrayList();
        List<JSONObject> rows_items = (List<JSONObject>) data.getOrDefault("rows_items", Collections.emptyList());
        List<JSONObject> items = (List<JSONObject>) data.getOrDefault("items", Collections.emptyList());
        rows_items.forEach(v -> {
            if (isOpenRow(v)) {
                res.add(getOpenRealcolV2(data, v, null));
            }
            items.forEach(s -> {
                if (isOpenOption(s)) {
                    res.add(getOpenRealcolV2(data, v, s));
                }
            });
        });
        return res;
    }

    @Override
    public List<String> getScoreColumnListV2(JSONObject data, QstructsDto qStruct) {
        List<String> res = new ArrayList();
        JSONObject scores = JSONObject.parseObject(qStruct.getScores());
        if (!scores.isEmpty() && scores.containsKey(data.getString("gid"))) {
            res.add(getScoreRealcolV2(data));
        }
        return res;
    }

    @Override
    public Map<String, Map<Object, Object>> getConvertTableV2(JSONObject q) {
        Map<String, Map<Object, Object>> convert_table = new HashMap();
        List<JSONObject> row_item = (List<JSONObject>) q.getOrDefault("rows_items", Collections.emptyList());
        row_item.forEach(item -> {
            String value = getSelectRealcolV2(q, item);
            convert_table.compute(value, (k, s) -> {
                if (Objects.isNull(s)) {
                    s = new HashMap<>(2);
                }
                s.put(item.get("gid"), BaseTypeHandler.clearHtml((String) item.get("title")));
                return s;
            });
        });
        return convert_table;
    }

    @Override
    public Map<Object, Object> getSelectAnswerDictV2(JSONObject dataValue, Object answers, String dtype, Boolean score_apply_type) {
        Map<Object, Object> data = new HashMap<>();
        List<JSONObject> rows_items = (List<JSONObject>) dataValue.getOrDefault("rows_items", Collections.emptyList());
        List<JSONObject> items = (List<JSONObject>) dataValue.getOrDefault("items", Collections.emptyList());
        Map<Integer, Object> item_dict = new HashMap<>();
        items.forEach(v -> {
            Map value = new HashMap(2);
            value.put("title", v.getString("title"));
            value.put("oid", v.getInteger("oid"));
            item_dict.put(v.getInteger("gid"), value);
        });
        if (Objects.isNull(answers)) {
            rows_items.forEach(row_item -> data.put(getSelectRealcolV2(dataValue, row_item), null));
        } else {
            rows_items.forEach(row_item -> {
                if (CollUtil.isNotEmpty((Map<String, List>) answers)) {
                    for (Map.Entry<String, List> entry : ((Map<String, List>) answers).entrySet()) {
                        String row_gid = entry.getKey();
                        List answer = entry.getValue();
                        if (row_item.getString("gid").equals(row_gid)) {
                            if (CollUtil.isNotEmpty(answer)) {
                                Map obj = (Map) item_dict.getOrDefault(answer.get(0), Collections.emptyMap());
                                if ("readable".equals(dtype)) {
                                    data.put(getSelectRealcolV2(dataValue, row_item), BaseTypeHandler.clearHtml((String) obj.getOrDefault("title", "")));
                                } else {
                                    data.put(getSelectRealcolV2(dataValue, row_item), obj.getOrDefault("oid", ""));
                                }
                            } else {
                                data.put(getSelectRealcolV2(dataValue, row_item), null);
                            }
                            break;
                        }
                    }
                } else {
                    data.put(getSelectRealcolV2(dataValue, row_item), null);
                }
            });
        }
        return data;
    }

    @Override
    public Map<Object, Object> getOpenAnswerDictV2(JSONObject dataValue, Object answerValue) {
        Map<Object, Object> data = new HashMap<>();
        List<JSONObject> items = (List<JSONObject>) dataValue.getOrDefault("items", Collections.emptyList());
        List<JSONObject> row_items = (List<JSONObject>) dataValue.getOrDefault("rows_items", Collections.emptyList());
        if (Objects.isNull(answerValue)) {
            row_items.forEach(row_item -> {
                if (isOpenRow(row_item)) {
                    data.put(getOpenRealcolV2(dataValue, row_item, null), null);
                }
                items.forEach(item -> {
                    if (isOpenOption(item)) {
                        data.put(getOpenRealcolV2(dataValue, row_item, item), null);
                    }
                });
            });
        } else {
            Map<String, Object> answers = (Map<String, Object>) answerValue;
            row_items.forEach(row_item -> {
                if (isOpenOption(row_item)) {
                    answers.forEach((row_gid, answer) -> {
                        if (row_gid.equals(String.format("%s_open", row_item.get("gid")))) {
                            data.put(getOpenRealcolV2(dataValue, row_item, null), BaseTypeHandler.clearHtml((String) answer));
                        }
                    });
                }
                answers.forEach((row_gid, answer) -> {
                    items.forEach(item -> {
                        if (row_gid.equals(row_item.get("gid"))) {
                            if (isOpenOption(item)) {
                                for (List<String> ans : ((List<List<String>>) answer)) {
                                    if (ans.get(0).equals(item.getString("seq")) && ans.size() > 1) {
                                        data.put(getOpenRealcolV2(dataValue, row_item, item), BaseTypeHandler.clearHtml(ans.get(1)));
                                        break;
                                    }
                                }
                                data.put(getOpenRealcolV2(dataValue, row_item, item), null);
                            }
                        }
                    });
                });
            });
        }
        return data;
    }


    @Override
    public Map<Object, Object> getScoreAnswerDictV2(JSONObject dataValue, Object answer, QstructsDto qstructsDto, JSONObject score_dict, String qtype) {
        Map<Object, Object> data = new HashMap<>();
        if (Objects.nonNull(qstructsDto) && StrUtil.isNotEmpty(qstructsDto.getScores()) && JSONObject.parseObject(qstructsDto.getScores()).containsKey(dataValue.getString("gid"))) {
            //np.nan 可以理解为null
            data.put(getScoreRealcolV2(dataValue), null);
        }
        Map<String, List<List>> answers = (Map<String, List<List>>) answer;
        if (CollUtil.isNotEmpty(answers)) {
            Float finalScore;
            try {
                AtomicReference<Float> score = new AtomicReference<>(0f);
                String gid = dataValue.getString("gid");
                answers.forEach((row, opts) -> {
                    String score_key = String.format("%s_%s_%s", gid, row, opts.get(0));
                    Float score_key_value;
                    if (StrUtil.isNotEmpty(row) && Objects.nonNull(score_key_value = score_dict.getFloat(score_key))) {
                        score.updateAndGet(v -> v + Float.parseFloat(String.format("%.2f", score_key_value)));
                    }
                });
                finalScore = score.get();
            } catch (Exception e) {
                log.error("分数转换异常：[}", e);
                //np.nan 可以理解为null
                finalScore = null;
            }
            data.put(getScoreRealcolV2(dataValue), finalScore);
        }
        return data;
    }

    @Override
    public List<List<String>> getVarLabelsV2(JSONObject dataValue, boolean not01, boolean need_title) {
        List<List<String>> data = new ArrayList<>();
        List<String> var_list = new ArrayList(), val_list = new ArrayList(), head_list = new ArrayList();
        List<JSONObject> rows_items = (List<JSONObject>) dataValue.getOrDefault("rows_items", Collections.emptyList());
        rows_items.forEach(row -> {
            var_list.add(String.format("VARIABLE LABELS %s__%s '%s:%s'.", dataValue.get("cid"), row.get("oid"), getUnquotedStr(dataValue.getString("title"), true), getTitles(dataValue, row, null, false)));
            head_list.add(String.format("%s__%s", dataValue.getString("cid"), row.get("oid")));
        });
        getValItemsV2(dataValue, head_list, val_list, true, true);
        data.add(var_list);
        data.add(val_list);
        return data;
    }

    @Override
    public List<String> getSpssCodeV2(JSONObject param, QstructsDto qstruct) {
        List<JSONObject> items = (List<JSONObject>) param.getOrDefault("items", Collections.emptyList());
        List<JSONObject> rows_items = (List<JSONObject>) param.getOrDefault("rows_items", Collections.emptyList());
        List<String> head_list = new ArrayList<>();
        rows_items.forEach(row -> {
            head_list.add(String.format("%s__%s", param.get("cid"), row.get("oid")));
            if (row.getBoolean("is_open") && row.getBoolean("is_open")) {
                head_list.add(String.format("%s__%s__open", param.get("cid"), row.get("oid")));
            }
            items.stream().forEach(item -> {
                if (item.getBoolean("is_open") && item.getBoolean("is_open")) {
                    head_list.add(String.format("%s__%s__%s__open", param.get("cid"), row.get("oid"), item.get("oid")));
                }
            });
        });
        if (ObjectUtil.isNotEmpty(qstruct.getScores()) && JSONObject.parseObject(qstruct.getScores()).containsKey(param.getString("gid"))) {
            head_list.add(getScoreRealcolV2(param));
        }
        return head_list;
    }

    @Override
    public String getQuestionTypeValue() {
        return QUESTION_TYPE_MATRIX_SINGLE.getValue();
    }
}
